home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
vol7n7.arc
/
PP707.ARC
/
LCVT.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-12-15
|
9KB
|
266 lines
name LCVT
title LCVT - format 32-bit number
page 55,132
;
;
; LCVT.ASM --- Convert signed long (32-bit) integer
; to formatted ASCII decimal string
;
; Copyright (C) 1988 Ziff Communications Co.
; PC Magazine * Ray Duncan
;
; Call with: BH = decimal places
; BL = field width
; CH = conversion flags
; bit meaning
; 7 = 0 if left justify
; 1 if right justify
; 6 = 0 fill field with *
; if number too large
; 1 truncate to fit
; 5 = 0 prefix with - only
; 1 prefix with + or -
; 4 = 0 pad with blanks
; 1 pad with char in CL
; 0-3 = reserved
; CL = pad character
; (if bit 4 of CH is set)
; DX:AX = 32-bit signed integer
; DS:SI = buffer to receive string
;
; Returns: if successful,
; Carry = clear
; DS:SI = formatted string
; AX = output field length
;
; if error (number too large,
; and bit 6 of CH was not set),
; Carry = set
; and output buffer filled with '*'
;
; DX destroyed, other registers preserved
;
; At least one significant digit is always stored.
; Calling this function with a field width of zero
; results in an error return.
DGROUP group _DATA
_DATA segment word public 'DATA'
buflen equ 16 ; length of working buffers
buf1 db buflen dup (?) ; LTOA builds string here
buf2 db buflen dup (?) ; formatted string built here
_DATA ends
; names for local variables
flags equ [bp-1] ; formatting flags
fpad equ [bp-2] ; pad character, if any
fdecpl equ [bp-3] ; decimal places in output
fwidth equ [bp-4] ; width of output field
fseg equ [bp-6] ; segment of output field
foffs equ [bp-8] ; offset of output field
fsign equ [bp-10] ; sign of original number
_TEXT segment word public 'CODE'
assume cs:_TEXT
extrn LTOA:near ; we will call the separately
; assembled LTOA routine
public lcvt ; make LCVT available to Linker
lcvt proc near ; format 32-bit integer
push es ; save registers
push di
push bp
push cx
push bx
mov bp,sp ; set up local variables
sub sp,10
mov fpad,cx ; save flags and pad char.
mov fwidth,bx ; save width and dec. places
mov fseg,ds ; save output field segment
mov foffs,si ; save output field offset
mov fsign,dx ; save sign of number
or bl,bl ; is output width zero?
jnz lcvt01 ; no, proceed
jmp lcvt15 ; error if width = zero
lcvt01: cmp bh,(buflen+2) ; too many decimal places?
jbe lcvt02 ; no, proceed
jmp lcvt14 ; error if buffer too small
lcvt02: or dx,dx ; test sign of number...
jns lcvt03 ; jump if number positive
neg dx ; negative, take abs. value
neg ax ; of number so we can control
sbb dx,0 ; sign placement
lcvt03: mov cx,10 ; use decimal base
mov si,DGROUP ; set DS:SI = local buffer
mov ds,si
mov si,offset DGROUP:buf1
call LTOA ; convert DX:AX to ASCII
; returns DS:SI -> string,
; AX = length
; now format the string...
add si,ax ; point to end of string
dec si ; returned by LTOA
mov cx,ax ; let CX = string length
push ds ; point to end of buffer
pop es ; for formatted string
mov di,offset DGROUP:buf2+buflen-1
std ; set direction flag
; for backwards move
xor bx,bx ; init. places counter
lcvt04: movsb ; transfer one char.
inc bx ; count characters
cmp bl,fdecpl ; need decimal point?
jne lcvt05 ; no, jump
mov al,'.' ; yes, store it
stosb
lcvt05: loop lcvt04 ; until all chars. transferred
cmp bl,fdecpl ; decimal taken care of?
ja lcvt08 ; yes, jump
je lcvt07 ; well, partially...
lcvt06: ; no, need decimal point
mov al,'0' ; store zeros up to
stosb ; decimal point
inc bx
cmp bl,fdecpl
jne lcvt06
mov al,'.' ; store decimal point
stosb
lcvt07: mov al,'0' ; force leading zero
stosb
lcvt08: ; was number negative?
test word ptr fsign,-1
jns lcvt09 ; no, jump
mov al,'-' ; yes, store '-' sign
stosb
jmp lcvt10
lcvt09: ; positive number, is
; '+' sign needed?
test byte ptr flags,20h
jz lcvt10 ; no, jump
mov al,'+' ; yes, store '+' sign
stosb
lcvt10: cld ; string now formatted
; with dec. point & sign
mov si,di ; copy address
inc si ; point to formatted string
; and calculate its length
mov ax,offset DGROUP:buf2+buflen
sub ax,si ; now AX = formatted length
mov es,fseg ; set ES:DI = address and
mov di,foffs ; CX = length of user's
mov cl,fwidth ; output buffer
xor ch,ch
jcxz lcvt15 ; return error if output
; field width = zero
cmp cx,ax ; is string too big for
; user's output field?
jae lcvt11 ; no, jump
; OK to truncate string?
test byte ptr flags,40h
jz lcvt14 ; no, error has occurred
mov ax,cx ; truncate formatted length
; to output field length
lcvt11: push ax ; save formatted length
mov al,' ' ; default pad char = blank
; test special padding flag
test byte ptr flags,10h
jz lcvt12 ; jump if use ASCII blank
mov al,fpad ; else use special char
lcvt12: rep stosb ; flood output field with
; padding character
mov di,foffs ; restore output buffer address
pop cx ; length of formatted string
; left or right justify?
test byte ptr flags,80h
jz lcvt13 ; jump if left justify
mov al,fwidth ; right justify, length of
xor ah,ah ; user's output buffer
sub ax,cx ; - formatted string length
add di,ax ; = offset into output field
lcvt13: rep movsb ; transfer formatted string
; to user's buffer
clc ; success signal: clear Carry
jmp lcvt16 ; go clean up and exit
lcvt14: ; error encountered, fill
; output field with '*' chars.
mov es,fseg ; ES:DI -> output field
mov di,foffs
mov cl,fwidth ; CX = output field length
xor ch,ch
mov al,'*' ; character = asterisk
rep stosb ; flood the output buffer
lcvt15: stc ; error signal: set Carry
lcvt16: mov ds,fseg ; return DS:SI = address
mov si,foffs ; of output field
mov al,fwidth ; AX = output field width
mov ah,0 ; (protect carry flag)
mov sp,bp ; discard local variables
pop bx ; restore registers
pop cx
pop bp
pop di
pop es
ret ; back to caller
lcvt endp
_TEXT ends
end